﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Kokomo.Mirror.CliMetadata.Tables;

namespace Kokomo.Mirror.CliMetadata
{
	class CliEventInfo : EventInfo
	{
		internal CliEventInfo(
			EventRow eventRow,
			CliMemberBasicInfo basicInfo
			)
		{
			this._eventRow = eventRow;
			this.basicInfo = basicInfo;
			this._methodSemanticLookup = new Lazy<ILookup<MethodSemanticsAttributes, int>>(this.LoadMethodSemantics);
			this._customAttributeData = new Lazy<IList<CustomAttributeData>>(this.LoadCustomAttributeData);
		}

		private CliMemberBasicInfo basicInfo;
		private EventRow _eventRow;

		#region Attributes

		private Lazy<IList<CustomAttributeData>> _customAttributeData;
		private IList<CustomAttributeData> LoadCustomAttributeData()
		{
			return this.basicInfo.module.GetCustomAttributesFor(this.MetadataToken);
		}
		public override IList<CustomAttributeData> GetCustomAttributesData()
		{
			return this._customAttributeData.Value;
		}
		#endregion

		public override EventAttributes Attributes
		{
			get { return this._eventRow.EventFlags; }
		}

		public override int MetadataToken
		{
			get { return this.basicInfo.token; }
		}

		public override Module Module
		{
			get { return this.basicInfo.module; }
		}

		private Lazy<ILookup<MethodSemanticsAttributes, int>> _methodSemanticLookup;
		private ILookup<MethodSemanticsAttributes, int> LoadMethodSemantics()
		{
			return this.basicInfo.module.QueryMethodSemantics(this.MetadataToken);
		}

		private IEnumerable<MethodInfo> GetSemanticMethods(MethodSemanticsAttributes semantics, bool nonPublic)
		{
			return this.basicInfo.module.QuerySemanticMethods(
				this.MetadataToken,
				this.DeclaringType,
				this.ReflectedType,
				semantics,
				nonPublic
				);
		}
		public override MethodInfo GetAddMethod(bool nonPublic)
		{
			return this.GetSemanticMethods(MethodSemanticsAttributes.AddOn, nonPublic).FirstOrDefault();
		}

		public override MethodInfo GetRaiseMethod(bool nonPublic)
		{
			return this.GetSemanticMethods(MethodSemanticsAttributes.Fire, nonPublic).FirstOrDefault();
		}

		public override MethodInfo GetRemoveMethod(bool nonPublic)
		{
			return this.GetSemanticMethods(MethodSemanticsAttributes.RemoveOn, nonPublic).FirstOrDefault();
		}

		public override MethodInfo[] GetOtherMethods(bool nonPublic)
		{
			return this.GetSemanticMethods(MethodSemanticsAttributes.Other, nonPublic).ToArray();
		}

		public override Type DeclaringType
		{
			get { return this.basicInfo.declaringType; }
		}

		public override object[] GetCustomAttributes(Type attributeType, bool inherit)
		{
			throw new NotImplementedException();
		}

		public override object[] GetCustomAttributes(bool inherit)
		{
			throw new NotImplementedException();
		}

		public override bool IsDefined(Type attributeType, bool inherit)
		{
			return this.basicInfo.module.IsAttributeDefinedOn(this.MetadataToken, attributeType, inherit);
		}

		public override string Name
		{
			get { return this.basicInfo.module.Metadata.GetString(this._eventRow.Name); }
		}

		public override Type ReflectedType
		{
			get { return this.basicInfo.reflectedType; }
		}
	}
}
